package main

import (
	"context"
	"errors"
	"fmt"
	"time"

	redis "github.com/go-redis/redis/v8"
)

// 基本使用
func base(rdb *redis.Client, ctx context.Context) {
	// 执行命令获取结果
	val, err := rdb.Get(ctx, "key").Result()
	fmt.Printf("result value:%v err:%v", val, err)

	// 先获取到命令对象
	cmder := rdb.Get(ctx, "key")
	fmt.Println(cmder.Val()) // 获取值
	fmt.Println(cmder.Err()) // 获取错误

	// 直接执行命令获取错误
	err = rdb.Set(ctx, "key", 10, time.Hour).Err() // 设置redis 字符串key:key,value:10,过期时间:1小时

	// 直接执行命令获取值
	value := rdb.Get(ctx, "key").Val()
	fmt.Println(value)
}

//  Do 执行任意命令
func doDemo(rdb *redis.Client, ctx context.Context) {
	err := rdb.Do(ctx, "set", "name", "kl", "EX", 3600).Err() // set name kl 3600
	fmt.Println(err)

	val, err := rdb.Do(ctx, "get", "name").Result() // get name
	fmt.Println(val, err)
}

// Nil错误表示Key不存在的情况
func getValueFromRedis(rdb *redis.Client, ctx context.Context) {
	val, err := rdb.Get(ctx, "hehe").Result()
	if err != nil {
		if errors.Is(err, redis.Nil) {
			fmt.Println("没有找到")
			return
		}
		fmt.Println("出错了:", err)
		return
	}
	fmt.Println("结果是：", val)
}

// zset示例
func zsetDemo(rdb *redis.Client, ctx context.Context) {
	// key
	zsetKey := "language_rank"
	// val
	languages := []*redis.Z{
		{Score: 90.0, Member: "Golang"},
		{Score: 98.0, Member: "Java"},
		{Score: 95.0, Member: "Python"},
		{Score: 97.0, Member: "JavaScript"},
		{Score: 99.0, Member: "C/C++"},
	}

	err := rdb.ZAdd(ctx, zsetKey, languages...).Err()
	if err != nil {
		fmt.Println("zadd failed,err:", err)
		return
	}
	fmt.Println("zadd success")

	// 把Golang的分数加10分
	newScore, err := rdb.ZIncrBy(ctx, zsetKey, 10.0, "Golang").Result()
	if err != nil {
		fmt.Println("zincryby failed,err:", err)
		return
	}
	fmt.Printf("Golang score is %f now.\n", newScore)

	// 取分数最高的3个
	ret := rdb.ZRevRangeWithScores(ctx, zsetKey, 0, 2).Val()
	for _, z := range ret {
		fmt.Println(z.Member, z.Score)
	}

	// 取95~100分的
	op := &redis.ZRangeBy{
		Min: "95",
		Max: "100",
	}
	ret, err = rdb.ZRangeByScoreWithScores(ctx, zsetKey, op).Result()
	if err != nil {
		fmt.Printf("zrangebyscore failed, err:%v\n", err)
		return
	}
	for _, z := range ret {
		fmt.Println(z.Member, z.Score)
	}
}

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // 密码
		DB:       0,  // 数据库
		PoolSize: 20, // 连接池大小
	})

	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel()

	// base(rdb, ctx)
	// doDemo(rdb, ctx)
	// getValueFromRedis(rdb, ctx)
	// zsetDemo(rdb, ctx)
}
